#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// buffer define
#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
// 指针
int in1 = 0;
int out1 = 0;
int in2 = 0;
int out2 = 0;
// 信号量
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;

pthread_cond_t wait_empty_buffer1;
pthread_cond_t wait_full_buffer1;
pthread_cond_t wait_empty_buffer2;
pthread_cond_t wait_full_buffer2;

int buffer1_is_empty()
{
    return in1 == out1;
}
int buffer2_is_empty()
{
    return in2 == out2;
}
int buffer1_is_full()
{
    return (in1 + 1) % CAPACITY == out1;
}
int buffer2_is_full()
{
    return (in2 + 1) % CAPACITY == out2;
}

int get1_item()
{
    int item;

    item = buffer1[out1];
    out1 = (out1 + 1) % CAPACITY;
    return item;
}

int get2_item()
{
    int item;

    item = buffer2[out2];
    out2 = (out2 + 1) % CAPACITY;
    return item;
}

void put1_item(int item)
{
    buffer1[in1] = item;
    in1 = (in1 + 1) % CAPACITY;
}

void put2_item(int item)
{
    buffer2[in2] = item;
    in2 = (in2 + 1) % CAPACITY;
}

void *consume(void *arg)
{
    int item;
    for (int i = 0; i < 8; i++)
    {
        pthread_mutex_lock(&mutex2);
        while (buffer2_is_empty())
        {
            pthread_cond_wait(&wait_full_buffer2, &mutex2);
        }
        // printf("here1\n");
        item = get2_item();
        printf("            consume item: %c\n", item);
        pthread_cond_signal(&wait_empty_buffer2);
        pthread_mutex_unlock(&mutex2);
    }
    return NULL;
}

void *calculate(void *arg)
{
    int item;
    for (int i = 0; i < 8; i++)
    {
        // 对第一个缓冲区的操作
        pthread_mutex_lock(&mutex1);
        while (buffer1_is_empty())
        {
            pthread_cond_wait(&wait_full_buffer1, &mutex1);
        }
        item = get1_item();
        pthread_mutex_unlock(&mutex1);
        item -= 32;
        // pthread_cond_signal(&wait_empty_buffer1);
        //  printf("here\n");

        // 对第二个缓冲区的操作
        pthread_mutex_lock(&mutex2);
        while (buffer2_is_full())
        {
            pthread_cond_wait(&wait_empty_buffer2, &mutex2);
        }
        put2_item(item);
        printf("    calculate item: %c\n", item);
        pthread_cond_signal(&wait_full_buffer2);
        pthread_mutex_unlock(&mutex2);

        pthread_cond_signal(&wait_empty_buffer1);
    }
    // return NULL;
}

void *produce(void *arg)
{
    int item;
    for (int i = 0; i < 8; i++)
    {
        pthread_mutex_lock(&mutex1);
        while (buffer1_is_full())
            pthread_cond_wait(&wait_empty_buffer1, &mutex1);

        item = 'a' + i;
        put1_item(item);
        printf("produce item: %c\n", item);
        pthread_cond_signal(&wait_full_buffer1);
        pthread_mutex_unlock(&mutex1);
    }
    return NULL;
}

int main()
{
    pthread_t consumer_tid;
    pthread_t calculate_tid;

    pthread_mutex_init(&mutex1, NULL);
    pthread_cond_init(&wait_empty_buffer1, NULL);
    pthread_cond_init(&wait_full_buffer1, NULL);
    pthread_mutex_init(&mutex2, NULL);
    pthread_cond_init(&wait_empty_buffer2, NULL);
    pthread_cond_init(&wait_full_buffer2, NULL);

    pthread_create(&consumer_tid, NULL, consume, NULL);
    pthread_create(&calculate_tid, NULL, calculate, NULL);
    produce(NULL);

    pthread_join(consumer_tid, NULL);
    pthread_join(calculate_tid, NULL);
    return 0;
}